//给你一个长桌子，桌子上盘子和蜡烛排成一列。给你一个下标从 0 开始的字符串 s ，它只包含字符 '*' 和 '|' ，其中 '*' 表示一个 盘子 ，'|'
// 表示一支 蜡烛 。 
//
// 同时给你一个下标从 0 开始的二维整数数组 queries ，其中 queries[i] = [lefti, righti] 表示 子字符串 s[left
//i...righti] （包含左右端点的字符）。对于每个查询，你需要找到 子字符串中 在 两支蜡烛之间 的盘子的 数目 。如果一个盘子在 子字符串中 左边和右边
// 都 至少有一支蜡烛，那么这个盘子满足在 两支蜡烛之间 。 
//
// 
// 比方说，s = "||**||**|*" ，查询 [3, 8] ，表示的是子字符串 "*||**|" 。子字符串中在两支蜡烛之间的盘子数目为 2 ，子字符
//串中右边两个盘子在它们左边和右边 都 至少有一支蜡烛。 
// 
//
// 请你返回一个整数数组 answer ，其中 answer[i] 是第 i 个查询的答案。 
//
// 
//
// 示例 1: 
//
// 
//
// 输入：s = "**|**|***|", queries = [[2,5],[5,9]]
//输出：[2,3]
//解释：
//- queries[0] 有两个盘子在蜡烛之间。
//- queries[1] 有三个盘子在蜡烛之间。
// 
//
// 示例 2: 
//
// 
//
// 输入：s = "***|**|*****|**||**|*", queries = [[1,17],[4,5],[14,17],[5,11],[15,16
//]]
//输出：[9,0,0,0,0]
//解释：
//- queries[0] 有 9 个盘子在蜡烛之间。
//- 另一个查询没有盘子在蜡烛之间。
// 
//
// 
//
// 提示： 
//
// 
// 3 <= s.length <= 105 
// s 只包含字符 '*' 和 '|' 。 
// 1 <= queries.length <= 105 
// queries[i].length == 2 
// 0 <= lefti <= righti < s.length 
// 
// Related Topics 数组 字符串 二分查找 前缀和 
// 👍 106 👎 0

package com.cute.leetcode.editor.cn;

import java.util.ArrayList;
import java.util.List;

public class PlatesBetweenCandles {
    public static void main(String[] args) {
        Solution solution = new PlatesBetweenCandles().new Solution();
    }
    //leetcode submit region begin(Prohibit modification and deletion)
    class Solution {
        /**
         * 使用了一个list顺序存储蜡烛的位置
         * 在每个要求的范围内使用二分法寻找离边界最近的蜡烛，然后根据坐标计算结果
         * 空间复杂度N，时间复杂度NlogN
         */
        public int[] platesBetweenCandles1(String s, int[][] queries) {
            List<Integer> list = new ArrayList<>();// 存放所有蜡烛的下标
            for (int i = 0; i < s.length(); i++) {
                if (s.charAt(i) == '|') list.add(i);
            }

            int[] res = new int[queries.length];//存放结果

            for(int i = 0; i < queries.length; i++){
                int left = queries[i][0];
                int right = queries[i][1];
                int begin, end;

                int l = 0;
                int r = list.size() - 1;
                int mid;
                while (l < r){// 找 >= left的第一根蜡烛下标
                    mid = l + (r - l) / 2;// 向下取整
                    if (list.get(mid) < left) l = mid + 1;
                    else r = mid;
                }
                begin = l;

                l = 0;
                r = list.size() - 1;
                while (l < r){// 找 <= right的第一根蜡烛下标
                    mid = l + (r - l) / 2 + 1;// 向上取整
                    if (list.get(mid) > right) r = mid - 1;
                    else l = mid;
                }
                end = l;

                if (end > begin) res[i] = (list.get(end) - list.get(begin) - 1) - (end - begin - 1);
            }
            return res;
        }

        /**
         * 使用前缀和以及记录最近距离蜡烛的方式求解
         * 因为给定s之后，下标i处左边和右边最近的蜡烛位置已经确定了
         * 然后遍历字符串的时候对盘子的数量进行统计
         */
        public int[] platesBetweenCandles(String s, int[][] queries) {
            char[] chars = s.toCharArray();
            int n = chars.length, m = queries.length;
            int[] l = new int[n], r = new int[n];//l和r分别保存下标i左边第一个和右边第一个蜡烛的位置
            int p = -1, q = -1;//记录蜡烛下标
            int[] sum = new int[n + 1];// 盘子数量前缀和
            for (int i = 0, j = n - 1; i < n; i++, j--) {
                if (chars[i] == '|') p = i;// 是蜡烛就更新
                if (chars[j] == '|') q = j;
                l[i] = p;
                r[j] = q;
                sum[i + 1] = sum[i] + (chars[i] == '*' ? 1 : 0);// 求前缀和
            }
            int[] res = new int[m];
            for (int i = 0; i < m; i++) {
                int a = queries[i][0], b = queries[i][1];
                int c = r[a], d = l[b];
                if (c != -1 && c < d) res[i] = sum[d + 1] - sum[c + 1];
            }
            return res;
        }
    }
//leetcode submit region end(Prohibit modification and deletion)

}




































